﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Input;
using ApartmentBillsManager.Start.Annotations;
using ApartmentBillsManager.Start.Common;
using ApartmentBillsManager.Start.Manager.Interfaces;
using ApartmentBillsManager.Start.Services;

namespace ApartmentBillsManager.Start.Manager
{
    class ApartmentManager : INotifyPropertyChanged, IContent
    {
        #region Data Members
        private Roommate _selectedRoommate;
        private List<DebtPresenter> _balance;
        private List<DebtPresenter> _debts;
        private Apartment _loadedApartment;
        private Bill _selectedBill;
        #endregion

        #region Ctor
        public ApartmentManager()
        {
            Debts = new List<DebtPresenter>();
            Balance = new List<DebtPresenter>();
        }
        #endregion

        #region Properties
        public Apartment LoadedApartment
        {
            get { return _loadedApartment; }
            set
            {
                _loadedApartment = value;
                OnPropertyChanged("LoadedApartment");
            }
        }

        public List<DebtPresenter> Balance
        {
            get { return _balance; }
            set
            {
                _balance = value;
                OnPropertyChanged("Balance");
            }
        }

        public List<DebtPresenter> Debts
        {
            get { return _debts; }
            set
            {
                _debts = value;
                OnPropertyChanged("Debts");
            }
        }

        public Roommate SelectedRoommate
        {
            get { return _selectedRoommate; }
            set
            {
                _selectedRoommate = value;
                OnPropertyChanged("SelectedRoommate");
            }
        }

        public Bill SelectedBill
        {
            get { return _selectedBill; }
            set
            {
                _selectedBill = value;
                OnPropertyChanged("SelectedBill");
            }
        }
        #endregion

        #region Public Methods
        public void LoadApartment(Apartment apartment)
        {
            LoadedApartment = apartment;

            if (LoadedApartment.OpenBills.Count() != 0)
                CalculateOpenBills();
            else
                Debts = new List<DebtPresenter>();
        }

        public void AddNewBill(object parameter)
        {
            var newBill = ObjectsFactory.CreateNewBill(LoadedApartment.Roommates);

            if (newBill != null)
                AddBillToLoadedApartmentOpenBills(newBill);
        }

        public void EditExistingBill(object existingBill)
        {
            var editedBill = ObjectsFactory.EditExistingBill(existingBill as Bill, LoadedApartment.Roommates);

            if (editedBill != null)
            {
                LoadedApartment.OpenBills.Remove(existingBill as Bill);
                AddBillToLoadedApartmentOpenBills(editedBill);
            }
        }

        public void PayDebt(object debtRow)
        {
            var debtPresenter = debtRow as DebtPresenter;

            if (debtPresenter != null)
            {
                LoadedApartment.UpdateBalace(debtPresenter.From, debtPresenter.To, debtPresenter.Amount);
            }

            Debts = new List<DebtPresenter>(BillsCalculator.GenerateDebts(LoadedApartment.Balance));

            if (Debts.Count == 0)
            {
                foreach (Bill openBill in LoadedApartment.OpenBills)
                {
                    openBill.DateClosed = DateTime.Now;
                    LoadedApartment.ClosedBills.Add(openBill);
                }

                LoadedApartment.OpenBills.Clear();
            }
        }
        #endregion

        #region Private Methods
        private void AddBillToLoadedApartmentOpenBills(Bill newBill)
        {
            LoadedApartment.OpenBills.Add(newBill);

            CalculateOpenBills();
        }

        private void CalculateOpenBills()
        {
            LoadedApartment.Balance = BillsCalculator.CalculateBalanceByAllBills(LoadedApartment);

            Debts = new List<DebtPresenter>(BillsCalculator.GenerateDebts(LoadedApartment.Balance));
        }
        #endregion

        #region Commands
        public ICommand AddNewBillCommand
        {
            get { return new DelegateCommand(AddNewBill); }
        }

        public ICommand EditExistingBillCommand
        {
            get { return new DelegateCommand(EditExistingBill); }
        }

        public ICommand PayDebtCommand
        {
            get { return new DelegateCommand(PayDebt); }
        }
        #endregion

        #region NotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion
    }
}
